package com.scpii.universal.dispatch;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import com.google.protobuf.InvalidProtocolBufferException;
import com.scpii.universal.concurrent.Callback;
import com.scpii.universal.concurrent.TaskPool;
import com.scpii.universal.dispatch.Const.DispathConfig;
import com.scpii.universal.dispatch.Const.IniConfig;
import com.scpii.universal.dispatch.domain.CompileTask;
import com.scpii.universal.dispatch.service.CompileTaskService;
import com.scpii.universal.dispatch.thread.PackThread;
import com.scpii.universal.dispatch.tools.PackTool;
import com.scpii.universal.pb.UniversalProtocol.CreatComplieTaskCS;
import com.scpii.universal.pb.UniversalProtocol.FinishComplieTask;
import com.scpii.universal.pb.UniversalProtocol.FinishTaskCS;
import com.scpii.universal.pb.UniversalProtocol.FinishTaskSC;
import com.scpii.universal.pb.UniversalProtocol.GetTaskCS;
import com.scpii.universal.pb.UniversalProtocol.GetTaskSC;
import com.scpii.universal.pb.UniversalProtocol.QryFinishComplieTaskCS;
import com.scpii.universal.pb.UniversalProtocol.QryFinishComplieTaskSC;
import com.scpii.universal.pb.UniversalProtocol.TaskSC;

@Component
public class Dispatcher implements Callback, InitializingBean {

	private static final Logger log = LoggerFactory.getLogger(Dispatcher.class);

	@Resource
	private CompileTaskService compileTaskService;

	@Resource
	private PackTool packTool;

	public static final Map<Integer, CompileTask> tasks = new ConcurrentHashMap<Integer, CompileTask>();

	private static int taskPoolNum = Integer
			.parseInt(DispathConfig.PACK_TASK_POOL_NUM);// 线程池处理线程数
	private static TaskPool<Void> taskPool = new TaskPool<Void>(taskPoolNum);// 打包线程池

	/**
	 * 添加编译任务
	 * 
	 * @param data
	 *            PB数据
	 * @return
	 * @throws InvalidProtocolBufferException
	 */
	public byte[] addCompileTask(byte[] data)
			throws InvalidProtocolBufferException {
		CreatComplieTaskCS creatComplieTaskCS = CreatComplieTaskCS
				.parseFrom(data);
		Integer appUpdateId = creatComplieTaskCS.getAppUpdateId();
		Integer osType = creatComplieTaskCS.getOsType();
		String appSign = creatComplieTaskCS.getAppSign();
		String appName = creatComplieTaskCS.getAppName();
		String appVersion = creatComplieTaskCS.getAppVersion();
		Integer styleId = creatComplieTaskCS.getStyleId();
		log.info("appUpdateId:" + appUpdateId + "/" + "osType:" + osType + "/"
				+ "appSign:" + appSign + "/" + "appName:" + appName);
		// 入db
		Integer compileTaskId = compileTaskService.getSeq();
		byte[] rs = compileTaskService.creatComplieTask(compileTaskId,
				appUpdateId, osType, appSign, appName, appVersion, styleId);
		// 入任务缓存并到添加到线程池
		dealAddCompileTask(compileTaskId, appUpdateId, osType, appSign,
				appName, appVersion, styleId);
		return rs;
	}

	/**
	 * 添加编译任务(入任务缓存并到添加到线程池)
	 * 
	 * @param intCompileTaskId
	 *            编译任务id
	 * @param intAppUpdateId
	 *            应用更新id
	 * @param intAppOsType
	 *            系统类型
	 * @param varAppSign
	 *            应用标示
	 * @param varAppName
	 *            应用名称
	 * @param appVersion
	 *            应用版本号
	 * @param intSytleId
	 *            风格类型
	 */
	private void dealAddCompileTask(Integer compileTaskId, Integer appUpdateId,
			Integer appOsType, String appSign, String appName,
			String appVersion, Integer styleId) {
		CompileTask task = new CompileTask();
		task.setCompileTaskId(compileTaskId);
		task.setAppUpdateId(appUpdateId);
		task.setAppOSType(appOsType);
		task.setAppSign(appSign);
		task.setAppName(appName);
		task.setStatus(Const.WAIT_PACK_STATE);
		task.setTaskStartTime(new Date());
		task.setConfigName(IniConfig.SYS_SIGN + appUpdateId + "_" + appVersion);
		task.setStyleId(styleId);
		tasks.put(compileTaskId, task);
		log.info("缓冲区任务队列为：" + tasks.size());
		taskPool.submitTask(new PackThread(task, this, packTool));
	}

	/**
	 * 当服务启动时添加数据库编译任务(入任务缓存并到添加到线程池)
	 */
	public void dealAddCompileTaskOnServerStartUp() {
		log.info("加载待打包任务并分发线程池执行开始");
		List<CompileTask> waitPackTasksList = compileTaskService
				.getTask(Const.WAIT_PACK_STATE);
		for (CompileTask task : waitPackTasksList) {
			tasks.put(task.getCompileTaskId(), task);
			taskPool.submitTask(new PackThread(task, this, packTool));
		}
		log.info("加载待打包任务并分发线程池执行结束");
		log.info("加载待编译任务开始");
		List<CompileTask> waitComplieTasksTasksList = compileTaskService
				.getWaitCompileTask();
		for (CompileTask task : waitComplieTasksTasksList) {
			tasks.put(task.getCompileTaskId(), task);
		}
		log.info("缓冲区任务队列为：" + tasks.size());
		log.info("加载待编译任务结束");
	}

	/**
	 * 获取待编译任务
	 * 
	 * @param data
	 *            PB数据
	 * @return
	 * @throws InvalidProtocolBufferException
	 */
	public byte[] getWaitCompileTask(byte[] data)
			throws InvalidProtocolBufferException {
		GetTaskCS cs = GetTaskCS.parseFrom(data);
		Integer appOSType = cs.getOSType();
		log.info("appOSType:" + appOSType);
		GetTaskSC.Builder builder = GetTaskSC.newBuilder();
		for (Entry<Integer, CompileTask> o : tasks.entrySet()) {
			CompileTask record = o.getValue();
			if (record.getAppOSType() == appOSType
					&& record.getStatus().equals(Const.COMPLETE_PACK_STATE)) {
				TaskSC.Builder builderItem = TaskSC.newBuilder();
				builderItem.setAppName(record.getAppName());
				builderItem.setTaskID(record.getCompileTaskId().intValue());
				builderItem.setConfigName(record.getConfigName() == null ? ""
						: o.getValue().getConfigName());
				builderItem.setAppSign(record.getAppSign());
				builderItem.setStyleId(record.getStyleId());
				builder.addItem(builderItem);
			}
		}
		log.info("缓冲区任务队列为：" + tasks.size());
		return builder.build().toByteArray();
	}

	/**
	 * 处理编译完成任务
	 * 
	 * @param data
	 *            PB数据
	 * @return
	 * @throws InvalidProtocolBufferException
	 */
	public byte[] dealFinishCompileTask(byte[] data)
			throws InvalidProtocolBufferException {
		FinishTaskCS finishTaskCS = FinishTaskCS.parseFrom(data);
		Integer taskId = finishTaskCS.getTaskID();
		int opCode = finishTaskCS.getOpCode();
		String fileName = finishTaskCS.getFileName();
		log.info("编译任务ID:" + taskId + "/状态 :" + opCode + "/文件名称：" + fileName);

		if (opCode == Const.OP_CODE_SUCESS) {
			/**
			 * 修改时间：2012-11-26 修改人：zuo liubo
			 * 修改内容：IOS编译生成2个文件，分别为appstore和gotoapp上面使用的
			 * ，根据文件的后缀名称来判断是否是IOS！</br>
			 * 如果是IOS这在数据库中的fileUrl进行处理，存储2个文件的路径，两个文件路径用","分隔
			 */

			StringBuffer ftpDirBuffer = new StringBuffer();
			ftpDirBuffer.append("http://").append(DispathConfig.FTP_HOST)
					.append("/").append(DispathConfig.FTP_STORE_DIR)
					.append("/");
			String ftpDir = ftpDirBuffer.toString();

			// 处理URL地址，如果是IOS的编译就将2个地址进行连接
			String fileUrl = ftpDir + fileName;
			if (fileName.endsWith("ipa")) {
				String appStoreFile = ftpDir
						+ fileName.substring(0, fileName.lastIndexOf("."))
						+ "_appstore.ipa";
				String gotoAppFile = ftpDir
						+ fileName.substring(0, fileName.lastIndexOf("."))
						+ "_gotoapp.ipa";
				fileUrl = appStoreFile + Const.IOS_FILENAME_SEPARATOR
						+ gotoAppFile;
			}
			log.info("编译成功后，写数据库操作！    文件下载路径为：" + fileUrl);
			compileTaskService.updateCompleteCompileTask(taskId, fileUrl);
			CompileTask task = tasks.get(taskId);
			if (task != null) {
				task.setStatus(Const.COMPLETE_COMPILE_STATE);
				task.setUrl(fileUrl);
			}
		} else {
			CompileTask task = tasks.get(taskId);
			if (task != null) {
				String erroMsg = Const.COMPILE_ERROR_MSG;
				compileTaskService.updateCompileTaskFaile(taskId, erroMsg);
				task.setStatus(Const.COMPILE_ERRO);
				task.setErroInfo(erroMsg);
			}
		}
		// 返回
		FinishTaskSC.Builder builder = FinishTaskSC.newBuilder();
		builder.setOpCode(Const.OP_CODE_SUCESS);
		log.info("缓冲区任务队列为：" + tasks.size());
		return builder.build().toByteArray();
	}

	/**
	 * 获取已完成编译的任务
	 * 
	 * @param data
	 *            PB数据
	 * @return
	 * @throws InvalidProtocolBufferException
	 */
	public byte[] getTaskByAppUpdateId(byte[] data)
			throws InvalidProtocolBufferException {
		QryFinishComplieTaskCS qryFinishComplieTaskCS = QryFinishComplieTaskCS
				.parseFrom(data);
		byte[] content = null;
		Integer appUpdateId = qryFinishComplieTaskCS.getAppUpdateId();
		for (Entry<Integer, CompileTask> o : tasks.entrySet()) {
			CompileTask record = o.getValue();
			if (record.getAppUpdateId().equals(appUpdateId)) {
				QryFinishComplieTaskSC.Builder builder = QryFinishComplieTaskSC
						.newBuilder();
				FinishComplieTask.Builder builderItem = FinishComplieTask
						.newBuilder();
				builderItem.setAppUpdateId(record.getAppUpdateId().intValue());
				builderItem.setConfigName(record.getConfigName() == null ? ""
						: record.getConfigName());
				builderItem.setUrl(record.getUrl() == null ? "" : record
						.getUrl());
				builderItem.setErroInfo(record.getErroInfo() == null ? ""
						: record.getErroInfo());
				builderItem.setStatus(record.getStatus());
				builder.addFinishComplieTask(builderItem);
				content = builder.build().toByteArray();
				break;
			}
		}
		if (content == null) {
			content = compileTaskService.getTaskByAppUpdateIdAsPb(appUpdateId);
		}
		log.info("缓冲区任务队列为：" + tasks.size());
		return content;
	}

	@Override
	public boolean handleMessage(int action, Object... data) {
		boolean isHandle = true;
		switch (action) {
		case Const.COMPLETE_PACK_ACTION:
			completePackTask((CompileTask) data[0]);
			break;
		case Const.UNCOMPLETE_PACK_ACTION:
			unCompletePackTask((CompileTask) data[0], (String) data[1]);
			break;
		default:
			isHandle = false;
			break;
		}
		return isHandle;
	}

	@Override
	public boolean handleMessage(Object... data) {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * 打包成功，修改任务为打包完毕状态（数据库及缓存更新）
	 * 
	 * @param task
	 */
	private void completePackTask(CompileTask task) {
		compileTaskService.updateCompletePackTask(task.getCompileTaskId());
		task.setStatus(Const.COMPLETE_PACK_STATE);
		tasks.put(task.getCompileTaskId(), task);
		log.info("缓冲区任务队列为：" + tasks.size());
	}

	/**
	 * 打包失败，修改任务为打包失败状态，并记录失败原因（数据库及缓存更新）
	 * 
	 * @param task
	 * @param erroMsg
	 */
	private void unCompletePackTask(CompileTask task, String erroMsg) {
		compileTaskService.updateCompileTaskFaile(task.getCompileTaskId(),
				erroMsg);
		task.setStatus(Const.COMPILE_ERRO);
		task.setErroInfo(erroMsg);
		tasks.put(task.getCompileTaskId(), task);
		log.info("缓冲区任务队列为：" + tasks.size());
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		dealAddCompileTaskOnServerStartUp();
	}

}
